using CollabApp.Domain.Services.Auth;
using CollabApp.Domain.Entities.Auth;
using CollabApp.Domain.Repositories;
using CollabApp.Application.Interfaces;
using System.Threading.Tasks;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;

namespace CollabApp.Application.Services.Auth;

/// <summary>
/// 认证服务实现
/// </summary>
public class AuthService : IAuthService
{
    private readonly IRepository<User> _userRep;
    private readonly IJwtTokenService _jwtTokenService;

    /// <summary>
    /// 认证服务实现
    /// </summary>
    /// <param name="userRep">用户仓储</param>
    /// <param name="jwtTokenService">JWT令牌服务</param>
    public AuthService(IRepository<User> userRep, IJwtTokenService jwtTokenService)
    {
        _userRep = userRep;
        _jwtTokenService = jwtTokenService;
    }

    /// <summary>
    /// 登录
    /// </summary>
    /// <param name="username">用户名</param>
    /// <param name="password">密码</param>
    /// <returns>JWT令牌</returns>
    public async Task<dynamic> LoginAsync(string username, string password, bool rememberMe = false)
    {
        // 1. 查找用户
        var user = await _userRep.GetSingleAsync(u => u.Username == username);
        if (user == null)
        {
            return new
            {
                Code = 1001,
                Message = "用户不存在，请重新输入！！！",
                Data = "用户不存在！"
            };
        }

        // 2. 校验密码（使用User实体的实例方法）
        if (!user.VerifyPassword(password))
        {
            return new
            {
                Code = 1002,
                Message = "密码错误，请重新输入！！！",
                Data = "密码错误！"
            };
        }

        // 3. 检查用户状态
        if (user.Status == UserStatus.Banned)
        {
            return new
            {
                Code = 1003,
                Message = "用户被封禁，请联系管理员！！！",
                Data = "用户被封禁！"
            };
        }

        // 4. 生成JWT令牌和刷新令牌
        var token = _jwtTokenService.GenerateToken(user.Id, user.Username);
        var refreshToken = Guid.NewGuid().ToString("N");
        var accessTokenExpires = DateTime.UtcNow.AddMinutes(120); // access token 2小时
        var refreshTokenExpires = rememberMe
            ? DateTime.UtcNow.AddDays(30) // 记住我：refresh token 30天
            : DateTime.UtcNow.AddDays(7); // 否则7天

        // 5. 设置令牌信息
        user.SetTokens(token, refreshToken, accessTokenExpires, refreshTokenExpires, rememberMe);
        await _userRep.UpdateAsync(user);
        await _userRep.SaveChangesAsync();

        // 6. 返回令牌和用户信息
        return new
        {
            Code = 1000,
            Message = "登录成功！",
            Data = new
            {
                Token = token,
                RefreshToken = refreshToken,
                AccessTokenExpires = accessTokenExpires,
                RefreshTokenExpires = refreshTokenExpires,
                User = new
                {
                    Id = user.Id,
                    Username = user.Username,
                    Nickname = user.Nickname,
                    AvatarUrl = user.AvatarUrl
                }
            }
        };
    }

    /// <summary>
    /// 注册
    /// </summary>
    /// <param name="username">用户名</param>
    /// <param name="password">密码</param>
    /// <param name="avatar">头像</param>
    /// <returns>注册结果</returns>
    public async Task<dynamic> RegisterAsync(string username, string password, string confirmPassword, string avatar)
    {
        // 0. 校验用户名和密码长度
        if (string.IsNullOrWhiteSpace(username) || username.Length < 3 || username.Length > 20)
        {
            return new
            {
                Code = 1003,
                Message = "用户名长度需为3-20个字符！",
                Data = "用户名长度不合法！"
            };
        }
        if (string.IsNullOrWhiteSpace(password) || password.Length < 6 || password.Length > 20)
        {
            return new
            {
                Code = 1004,
                Message = "密码长度需为6-20个字符！",
                Data = "密码长度不合法！"
            };
        }

        // 1. 检查用户名是否已存在
        var existUser = await _userRep.GetSingleAsync(u => u.Username == username);
        if (existUser != null)
        {
            return new
            {
                Code = 1001,
                Message = "用户名已存在，请重新输入！！！",
                Data = "用户名已存在！"
            };
        }

        // 2. 校验两次密码一致性
        if (password != confirmPassword)
        {
            return new
            {
                Code = 1002,
                Message = "两次输入的密码不一致，请重新输入！",
                Data = "密码不一致！"
            };
        }

        // 3. 创建新用户（用username作为nickname参数，领域层实体不变）
        var user = User.Create(username, password, username);
        // 设置头像
        if (!string.IsNullOrWhiteSpace(avatar))
        {
            user.UpdateProfile(user.Nickname, avatar);
        }

        // 4. 保存到仓储
        await _userRep.AddAsync(user);
        await _userRep.SaveChangesAsync();

        // 5. 返回注册成功信息
        return new
        {
            Code = 1000,
            Message = "注册成功，请前往登录界面登录！",
            Data = "注册成功！"
        };
    }

    /// <summary>
    /// 刷新令牌
    /// </summary>
    /// <param name="refreshToken">刷新令牌</param>
    /// <returns>新的JWT令牌</returns>
    public async Task<dynamic> RefreshTokenAsync(string refreshToken)
    {
        // 1. 查找用户
        var user = await _userRep.GetSingleAsync(u => u.RefreshToken == refreshToken);
        if (user == null)
        {
            return new
            {
                Code = 1001,
                Message = "无效的刷新令牌！",
                Data = "RefreshToken无效！"
            };
        }

        // 2. 校验刷新令牌是否过期
        if (!user.RefreshTokenExpiresAt.HasValue || user.RefreshTokenExpiresAt.Value < DateTime.UtcNow)
        {
            return new
            {
                Code = 1002,
                Message = "刷新令牌已过期，请重新登录！",
                Data = "RefreshToken已过期！"
            };
        }

        // 3. 检查用户状态
        if (user.Status == UserStatus.Banned)
        {
            return new
            {
                Code = 1003,
                Message = "用户被封禁，请联系管理员！",
                Data = "用户被封禁！"
            };
        }

        // 4. 生成新accessToken和新的refreshToken（可选，安全性更高）
        var newAccessToken = _jwtTokenService.GenerateToken(user.Id, user.Username);
        var newRefreshToken = Guid.NewGuid().ToString("N");
        var newAccessTokenExpires = DateTime.UtcNow.AddMinutes(120);
        var newRefreshTokenExpires = DateTime.UtcNow.AddDays(7);

        // 5. 更新用户令牌信息
        user.SetTokens(newAccessToken, newRefreshToken, newAccessTokenExpires, newRefreshTokenExpires);
        await _userRep.UpdateAsync(user);
        await _userRep.SaveChangesAsync();

        // 6. 返回新令牌
        return new
        {
            Code = 1000,
            Message = "令牌刷新成功！",
            Data = new
            {
                Token = newAccessToken,
                RefreshToken = newRefreshToken,
                AccessTokenExpires = newAccessTokenExpires,
                RefreshTokenExpires = newRefreshTokenExpires
            }
        };
    }

    /// <summary>
    /// 忘记密码（重置密码）
    /// </summary>
    /// <param name="username">用户名</param>
    /// <param name="newPassword">新密码</param>
    /// <returns>操作结果</returns>
    public async Task<dynamic> ForgotPasswordAsync(string username, string newPassword)
    {
        var user = await _userRep.GetSingleAsync(u => u.Username == username);
        if (user == null)
        {
            return new
            {
                Code = 1001,
                Message = "用户不存在！",
                Data = (string?)null
            };
        }
        if (string.IsNullOrWhiteSpace(newPassword) || newPassword.Length < 6 || newPassword.Length > 20)
        {
            return new
            {
                Code = 1002,
                Message = "新密码长度需为6-20位！",
                Data = (string?)null
            };
        }
        user.UpdatePassword(newPassword);
        await _userRep.UpdateAsync(user);
        await _userRep.SaveChangesAsync();
        return new
        {
            Code = 1000,
            Message = "密码重置成功！请返回登录。",
            Data = (string?)null
        };
    }

}